{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# One Port Tiered Calibration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Intro" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A one-port network analyzer can be used to measure a two-port device, provided that the device is reciprocal. This is accomplished by performing two calibrations, which is why its called a *tiered* calibration. \n", "\n", "First, the VNA is calibrated at the test-port like normal. This is called the *first tier*. Next, the device is connected to the test-port, and a calibration is performed at the far end of the device, the *second tier*. A diagram is shown below,\n", "\n", "![box diagram](oneport_tiered_calibration/images/boxDiagram.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook will demonstrate how to use [skrf](http://scikit-rf.org) to do a two-tiered one-port calibration. We'll use data that was taken to characterize a waveguide-to-CPW probe. So, for this specific example the diagram above looks like:\n", "\n", "![probe diagram](oneport_tiered_calibration/images/probe.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Some Data " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The data available is the folders `'tier1/'` and `'tier2/'`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!ls {\"oneport_tiered_calibration/\"}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(if you dont have the git repo for these examples, the data for this notebook can be found [here](https://github.com/scikit-rf/scikit-rf/tree/master/doc/source/examples/metrology/oneport_tiered_calibration))\n", "\n", "In each folder you will find the two sub-folders, called `'ideals/' ` and `'measured/'`. These contain touchstone files of the calibration standards ideal and measured responses, respectively. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!ls {\"oneport_tiered_calibration/tier1/\"}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first tier is at waveguide interface, and consisted of the following set of standards\n", "\n", "* short \n", "* delay short\n", "* load\n", "* radiating open (literally an open waveguide)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!ls {\"oneport_tiered_calibration/tier1/measured/\"}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating Calibrations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tier 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First defining the calibration for *Tier 1*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "import skrf as rf\n", "from skrf.calibration import OnePort\n", "from skrf.io.general import read_all_networks\n", "\n", "%matplotlib inline\n", "\n", "rf.stylely()\n", "\n", "\n", "tier1_ideals = read_all_networks('oneport_tiered_calibration/tier1/ideals/')\n", "tier1_measured = read_all_networks('oneport_tiered_calibration/tier1/measured/')\n", "\n", "\n", "tier1 = OnePort(measured = tier1_measured,\n", " ideals = tier1_ideals,\n", " name = 'tier1',\n", " sloppy_input=True)\n", "tier1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because we saved corresponding *ideal* and *measured* standards with identical names, the Calibration will automatically align our standards upon initialization. (More info on creating Calibration objects this can be found in [the docs](../../tutorials/Calibration.ipynb).)\n", "\n", "Similarly for the second tier 2," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tier 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tier2_ideals = read_all_networks('oneport_tiered_calibration/tier2/ideals/')\n", "tier2_measured = read_all_networks('oneport_tiered_calibration/tier2/measured/')\n", "\n", "\n", "tier2 = OnePort(measured = tier2_measured,\n", " ideals = tier2_ideals,\n", " name = 'tier2',\n", " sloppy_input=True)\n", "tier2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Error Networks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each one-port Calibration contains a two-port error network, that is determined from the calculated error coefficients. The error network for *tier1* models the VNA, while the error network for *tier2* represents the VNA **and** the DUT. These can be visualized through the parameter `'error_ntwk'`.\n", "\n", "\n", "For tier 1, " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tier1.error_ntwk.plot_s_db()\n", "plt.title('Tier 1 Error Network')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly for tier 2, " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tier2.error_ntwk.plot_s_db()\n", "plt.title('Tier 2 Error Network')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## De-embedding the DUT" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As previously stated, the error network for *tier1* models the VNA, and the error network for *tier2* represents the VNA+DUT. So to determine the DUT's response, we cascade the inverse S-parameters of the VNA with the VNA+DUT. \n", "\n", "$$ DUT = VNA^{-1}\\cdot (VNA \\cdot DUT)$$\n", "\n", "In skrf, this is done as follows" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dut = tier1.error_ntwk.inv ** tier2.error_ntwk\n", "dut.name = 'probe'\n", "dut.plot_s_db()\n", "plt.title('Probe S-parameters')\n", "plt.ylim(-60,10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You may want to save this to disk, for future use, \n", "\n", " dut.write_touchstone()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!ls {\"probe*\"}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.5" } }, "nbformat": 4, "nbformat_minor": 1 }